package e.odbo.data.dsl;

import e.odbo.data.dsl.query.QBFParameters;
import e.odbo.data.dsl.operation.QueryOperation;
import e.odbo.data.dsl.func.FORMATFunction;
import e.odbo.data.dsl.func.MIDFunction;
import e.odbo.data.dsl.func.ROUNDFunction;

import java.util.*;

public class Select {
    boolean distinct=false;
    Object[] selectColumns;
    Table[] tables;
    QBFParameters qbfParameters;
    QueryOperation queryOperation=new QueryOperation();
    Object[] groups;
    QBFParameters having;

    Select unionSelect;
    List<Join> joins=new ArrayList<>();

    public Select(Object[] selectColumns) {
        this.selectColumns = selectColumns;
    }

    public boolean isDistinct() {
        return distinct;
    }

    public Object[] getSelectColumns() {
        return selectColumns;
    }

    public Table[] getTables() {
        return tables;
    }

    public QBFParameters getQbfParameters() {
        return qbfParameters;
    }

    public Object[] getGroups() {
        return groups;
    }

    public QBFParameters getHaving() {
        return having;
    }

    public Select getUnionSelect() {
        return unionSelect;
    }

    public List<Join> getJoins() {
        return joins;
    }

    public QueryOperation getQueryOperation(){
        return queryOperation;
    }

    //------------>>

    public static Select c(Object ...value){
        return new Select(value);
    }


    public Select distinct(){
        this.distinct=true;
        return this;
    }

    public Select from(String ...tables){
        this.tables=new Table[tables.length];
        for(int i=0;i<tables.length;i++)
            this.tables[i]=new Table(tables[i]);
        return this;
    }

    public Select from(Table ...tables){
        this.tables=tables;
        return this;
    }

    public Select where(QBFParameters qbfParameters){
        this.qbfParameters=qbfParameters;
        return this;
    }

    public Select ext(QueryOperation queryOperation){
        this.queryOperation=queryOperation;
        return this;
    }

    public Select orderBy(String column){
        queryOperation.order(column);
        return this;
    }

    public Select orderBy(String column,boolean asc){
        queryOperation.order(column,asc);
        return this;
    }

    public Select page(int pageNum,int pageSize){
        queryOperation.page(pageNum,pageSize);
        return this;
    }

    public Select groupBy(String ...value){
        this.groups=value;
        return this;
    }

    public Select having(QBFParameters qbfParameters){
        this.having=qbfParameters;
        return this;
    }

    public void UNION(Select select){
        this.unionSelect=select;
    }


    public static class Table{
        String tableName;
        String alise;
        Select subSelect;

        public Table(String tableName) {
            this.tableName = tableName;
        }

        public Table(Select subSelect) {
            this.subSelect = subSelect;
        }

        public Table AS(String alise){
            this.alise=alise;
            return this;
        }

        public String getTableName() {
            return tableName;
        }

        public String getAlise() {
            return alise;
        }

        public Select getSubSelect() {
            return subSelect;
        }
    }

    public static Table TABLE(String tableName){
        return new Table(tableName);
    }

    public static Table TABLE(Select select){
        return new Table(select);
    }

    //getSQL
    public static ColumnFunction COUNT(){
        return COUNT("*");
    }

    public static ColumnFunction<String> COUNT(String columnName){
        return new ColumnFunction<String>("COUNT",columnName){};
    }

    public static ColumnFunction COLUMN(String columnName){
        return new ColumnFunction("column",columnName){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }


    public static ColumnFunction<Number> AVG(String column){
        return new ColumnFunction<Number>("AVG",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> FIRST(String column){
        return new ColumnFunction<String>("FIRST",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> LAST(String column){
        return new ColumnFunction<String>("LAST",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> MAX(String column){
        return new ColumnFunction<String>("MAX",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> MIN(String column){
        return new ColumnFunction<String>("MIN",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<Number> SUM(String column){
        return new ColumnFunction<Number>("SUM",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> UCASE(String column){
        return new ColumnFunction<String>("UCASE",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> LCASE(String column){
        return new ColumnFunction<String>("LCASE",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> MID(String column,int start){
        return new MIDFunction(column,start);
    }

    public static ColumnFunction<String> MID(String column,int start,int length){
        return new MIDFunction(column,start,length);
    }


    public static ColumnFunction<String> LEN(String column){
        return new ColumnFunction<String>("LEN",column){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> ROUND(String column,int decimals){
        return new ROUNDFunction(column,decimals);
    }

    public static ColumnFunction<Date> NOW(){
        return new ColumnFunction<Date>("NOW"){
            public String getColumnName() {
                return this.columnName;
            }
        };
    }

    public static ColumnFunction<String> FORMAT(String column,String format){
        return new FORMATFunction(column,format);
    }

    //join
    public Join join(String table){
        Join join=new Join(JOIN.InnerJOIN,table,this);
        this.joins.add(join);
        return join;
    }

    public Join leftJOIN(String table){
        Join join=new Join(JOIN.LeftJOIN,table,this);
        this.joins.add(join);
        return join;
    }

    public Join rightJOIN(String table){
        Join join=new Join(JOIN.RightJOIN,table,this);
        this.joins.add(join);
        return join;
    }

    public Join fullJOIN(String table){
        Join join=new Join(JOIN.FullJOIN,table,this);
        this.joins.add(join);
        return join;
    }

    public  enum JOIN {
        LeftJOIN("LEFT JOIN"),RightJOIN("RIGHT JOIN"),FullJOIN("FULL JOIN"),InnerJOIN("INNER JOIN");
        private String name;

        JOIN(String name) {
            this.name=name;
        }

        public String getName(){
            return name;
        }
    }

}
